﻿/*
Copyright (c) 2010 Vratislav Cermak (vratacermak@gmail.com)
 
This file is part of TeachMe Project. See http://code.google.com/p/teach-me for more information.
 
TeachMe is an open source project. Using of TeachMe is free of charge.
It is distributed under GNU General Public License version 3 (GPLv3).
GPLv3 can be found at http://www.gnu.org/licenses/gpl.html.
 
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using System.Xml.Serialization;

namespace TeachMe.Application.Controls
{
    public class Progress : Panel
    {
        [XmlType("ProgressItem")]
        public class Item
        {
            public string Text { get; set; }
            public event EventHandler<EventArgs> Clicked;
            public bool Pressed { get; set; }

            internal void InvokeClicked()
            {
                EventHandler<EventArgs> handler = Clicked;
                if (handler != null)
                {
                    handler(this, EventArgs.Empty);
                }
            }
        }

        private List<Item> _items;
        private Color _penColor;
        private Color _contentColor;
        private Color _textColor;
        private int _penWidth;
        private int _radius;
        private bool _antiAliasing;

        private readonly Font _normalFont;
        private readonly Font _pressedFont;

        public Progress()
        {
            SetStyle(ControlStyles.DoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);

            _normalFont = new Font(FontFamily.GenericSerif, 8, FontStyle.Regular);
            _pressedFont = new Font(FontFamily.GenericSerif, 8, FontStyle.Bold);
        }

        public List<Item> Items
        {
            get
            {
                return _items;
            }
            set
            {
                _items = value;

                Invalidate();
            }
        }

        public int PenWidth
        {
            get
            {
                return _penWidth;
            }
            set
            {
                _penWidth = value;

                Invalidate();
            }
        }

        public Color PenColor
        {
            get
            {
                return _penColor;
            }
            set
            {
                _penColor = value;

                Invalidate();
            }
        }

        public int Radius
        {
            get
            {
                return _radius;
            }
            set
            {
                _radius = value;

                Invalidate();
            }
        }

        public Color ContentColor
        {
            get
            {
                return _contentColor;
            }
            set
            {
                _contentColor = value;

                Invalidate();
            }
        }

        public Color TextColor
        {
            get
            {
                return _textColor;
            }
            set
            {
                _textColor = value;

                Invalidate();
            }
        }

        public bool AntiAliasing
        {
            get
            {
                return _antiAliasing;
            }
            set
            {
                _antiAliasing = value;

                Invalidate();
            }
        }

        private int CalculateWidth(int idx)
        {
            using (Graphics graphics = CreateGraphics())
            {
                return (int) graphics.MeasureString(_items[idx].Text, _normalFont).Width + 25;
            }
        }

        private void CalculateWidth(out int width, out int height)
        {
            using (Graphics graphics = CreateGraphics())
            {
                width = 0;

                for (int idx = 0; idx < _items.Count; idx++)
                {
                    SizeF measures = graphics.MeasureString(_items[idx].Text, _normalFont);
                    width += (int)measures.Width;
                    if (idx + 1 < _items.Count)
                    {
                        width += 25;
                    }
                    else
                    {
                        width += 15;
                    }
                }

                height = (int) graphics.MeasureString("ace", _normalFont).Height;
            }
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            if (_items == null || _items.Count == 0)
            {
                return;
            }

            if (_penWidth <= 0)
            {
                return;
            }

            if (_radius <= 0)
            {
                return;
            }

            if (AntiAliasing)
            {
                e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
                e.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
            }

            ExtendedGraphics graphics = new ExtendedGraphics(e.Graphics);

            int itemsWidth;
            int itemsHeight;

            CalculateWidth(out itemsWidth, out itemsHeight);

            graphics.FillRoundRectangle(new SolidBrush(_contentColor), 4, 4, itemsWidth, Height - 8, _radius);
            graphics.DrawRoundRectangle(new Pen(_penColor, _penWidth), 4, 4, itemsWidth, Height - 8, _radius);

            int left = 10;

            for (int idx = 0; idx < _items.Count; idx++)
            {
                int top = ((Height / 2) - (itemsHeight / 2)) - 2;

                if (_items[idx].Pressed)
                {
                    e.Graphics.DrawString(_items[idx].Text, _pressedFont, new SolidBrush(TextColor), left, top);
                }
                else
                {
                    e.Graphics.DrawString(_items[idx].Text, _normalFont, new SolidBrush(TextColor), left, top);
                }
                left += CalculateWidth(idx);

                if (idx + 1 < _items.Count)
                {
                    e.Graphics.DrawLines(new Pen(_penColor, _penWidth), new[] { new Point(left - 20, 4), new Point(left - 10, Height / 2), new Point(left - 20, Height - 4) });
                }
            }
        }
    }
}
